/*
 * StandardSimulation.java
 *
 * Created on 20 maj 2007, 22:02
 */

package edu.uj.petri.simulation;

import edu.uj.petri.commands.Command;
import edu.uj.petri.commands.TransitionFiringCommand;
import edu.uj.petri.document.Document;
import edu.uj.petri.gui.MainWindowInterface;
import edu.uj.petri.model.Model;
import edu.uj.petri.model.Transition;
import edu.uj.util.Observer;
import edu.uj.util.ObserverList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ResourceBundle;

/**
 * @author Lukasz, Piotrek
 */
public class StandardSimulation implements Simulation {
    
    private ObserverList observerList;
    
    private ArrayList<Transition> firedTransitions;
    
    private Document document;
    
    private String errorMessage="?";
    
    /** Creates a new instance of StandardSimulation */
    public StandardSimulation() {
        observerList = new ObserverList();
        firedTransitions = new ArrayList<Transition>();
    }
    
    public void showAllActiveTransitions() {
        Model model = document.getModel();
        model.clearActiveTransitions();
        Collection<Transition> active = model.findActiveTransitions();
        for(Transition transition : active)
            transition.activate();
    }
    
    /**
     * method for private class use - creates command for firing single transition
     * and fires it. No checks are done.
     * @author Piotrek
     */
    private void fire(Transition transition) {
        Command command = new TransitionFiringCommand(transition, document.getModel(), this);
        document.execute(command);
    }

    public void fireTransition(Transition transition) throws SimulationException {
        // TODO perhaps in another way?
        if (!transition.canBeFired())
            throw new SimulationException(String.format(ResourceBundle.getBundle("edu/uj/petri/messages").getString(
                    "transition_%s_unable_to_be_fired"), transition.getName()));
        this.fire(transition);
    }

    public void fireTransitions(List<Transition> transitions, int delayMs) {
        // TODO finish
        
        for (Transition t : transitions) { // use thread?
            // fire etc.
            if (!t.canBeFired()) {
                // save error message so that it can be read through getErrorMessage()
                setErrorMessage(String.format(ResourceBundle.getBundle("edu/uj/petri/messages").getString(
                        "transition_%s_unable_to_be_fired"), t.getName()));
                observerList.notifyAllSubscribers(SIMULATION_ERROR);
                break;
            }
            this.fire(t);
        }
    }

    public void fireRandomTransitions(int number, int delayMs) {
        Model model = document.getModel();
        for (int i=0; i<number; ++i) {
            Collection<Transition> active = model.findActiveTransitions();
            int count = active.size();
            
            if (count == 0)
                return;
            
            int chosenNo = (int)Math.floor(Math.random()*count);
            
            Transition chosen=null;
            int j=0;
            for(Transition t : active) {
                if (j==chosenNo) {
                    chosen = t;
                    break;
                }
                ++j;
            }
            
            fire(chosen);
            
            try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
        // TODO finish
    }

    public void initialise(edu.uj.petri.document.Document document) {
        this.document = document;
    }
    
    public void finish() {
        document.getModel().clearActiveTransitions();
        observerList.clear();
    }

    public void pushFiredTransition(Transition fired) {
        firedTransitions.add(fired);
        observerList.notifyAllSubscribers(TRANSITION_ADDED);
    }

    public void popFiredTransition() {
        firedTransitions.remove(firedTransitions.size()-1);
        observerList.notifyAllSubscribers(TRANSITION_DELETED);
    }

    public void reset() {
        firedTransitions.clear(); // remove all transitions
        observerList.notifyAllSubscribers(CLEAR_TRANSITIONS);
    }

    public void applyTo(MainWindowInterface window) {
        subscribe(window);
        observerList.notifyAllSubscribers(TRANSITION_REFRESH);
    }

    public void subscribe(Observer o) {
        observerList.subscribe(o);
    }

    public void unsubscribe(Observer o) {
        observerList.unsubscribe(o);
    }

    public Transition getLastFiredTransition() {
        return firedTransitions.get(firedTransitions.size()-1);
        // TODO index check?
    }

    public List<Transition> getAllFiredTransitions() {
        return firedTransitions;
    }
    
    private void setErrorMessage(String msg) {
        errorMessage=msg;
    }

    public String getErrorMessage() {
        return errorMessage;
    }
    
}
